package com.dragon.annotation;

import javax.persistence.*;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 默认实现的解析器
 *
 * @author dragon
 * @since 2019/12/3
 */
public class DefaultParser implements Parser {

    /**
     * 解析entity的解析器
     *
     * @param classList entityClassList
     * @return java.util.List<com.dragon.annotation.EntityTable>
     */
    @Override
    public List<EntityTable> parse(List<Class<?>> classList) {
        if (classList == null || classList.size() == 0) {
            return null;
        }
        ArrayList<EntityTable> entityTableList = new ArrayList<>();
        classList.forEach(clazz -> {
            doParse(clazz, entityTableList);
        });

        return entityTableList;
    }

    /**
     * 真正的解析方法
     *
     * @param clazz           被解析的Class对象
     * @param entityTableList 结果集
     */
    private void doParse(Class<?> clazz, List<EntityTable> entityTableList) {
        if (clazz == null) {
            return;
        }
        // 解析表
        EntityTable entityTable = doParseTable(clazz);
        if (entityTable == null) {
            return;
        }
        // 解析列
        doParseColumns(clazz, entityTable);

        entityTableList.add(entityTable);
    }

    /**
     * 解析@Table,生成EntityTable
     *
     * @param clazz Class对象
     * @return com.dragon.annotation.EntityTable
     */
    private EntityTable doParseTable(Class<?> clazz) {
        if (!clazz.isAnnotationPresent(Table.class)) {
            return null;
        }
        EntityTable entityTable = new EntityTable();

        // 解析表名
        Table annotation = clazz.getAnnotation(Table.class);
        entityTable.setName(annotation.name());
        /*
         * 解析唯一约束
         */
        UniqueConstraint[] uniqueConstraints = annotation.uniqueConstraints();
        for (UniqueConstraint uniqueConstraint : uniqueConstraints) {
            for (String columnName : uniqueConstraint.columnNames()) {
                entityTable.getUniqueConstraintColumnList().add(columnName);
            }
        }

        return entityTable;
    }

    /**
     * 解析@Column，生成EntityColumn
     *
     * @param clazz       被解析的Class对象
     * @param entityTable 实体表对象
     */
    private void doParseColumns(Class<?> clazz, EntityTable entityTable) {
        Field[] fields = clazz.getDeclaredFields();
        Arrays.stream(fields)
                .filter(Objects::nonNull)
                .forEach(
                        field -> {
                            if (field.isAnnotationPresent(Id.class)) {
                                doParsePrimaryKey(field, entityTable);
                            }
                            if (field.isAnnotationPresent(Column.class)) {
                                doParseColumn(field, entityTable);
                            }
                        }
                );
    }

    /**
     * 解析主键
     *
     * @param field       被解析的字段
     * @param entityTable 实体表对象
     */
    private void doParsePrimaryKey(Field field, EntityTable entityTable) {
        // 设置主键的列名
        String idName = field.getName();
        entityTable.setPrimaryKeyName(idName);
        // 设置主键是否是自动增长
        GeneratedValue generatedValueAnnotation = field.getDeclaredAnnotation(GeneratedValue.class);
        if (generatedValueAnnotation != null) {
            if (GenerationType.IDENTITY.equals(generatedValueAnnotation.strategy())) {
                entityTable.setAutoIncrement(true);
            }
        }
    }

    /**
     * 解析列
     *
     * @param field       被解析的字段
     * @param entityTable 实体表对象
     */
    private void doParseColumn(Field field, EntityTable entityTable) {
        Column columnAnnotation = field.getAnnotation(Column.class);
        EntityColumn entityColumn = new EntityColumn();
        entityColumn.setName(columnAnnotation.name());
        entityColumn.setColumnDefinition(columnAnnotation.columnDefinition());
        entityColumn.setNullable(columnAnnotation.nullable());

        entityTable.getEntityClassColumns().add(entityColumn);
    }
}
